﻿#include "VulkanViewportWidget.h"
#include "Render/VulkanContext.h"
#include "Render/Scene/DefferRenderAttachments.h"
#include "Render/Scene/AntiAliasingAttachments.h"
#include "Render/Scene/RenderScene.h"
#include "Render/Texture/GPURenderTarget.h"
#include "Render/Widget/VulkanWindow.h"
#include "Render/PixelObject/VulkanPixelObjects.h"

CVulkanViewportWidgets::~CVulkanViewportWidgets()
{
    //销毁command buffer
    CVulkanContext::Get()->GetRecycleObjects()->CommandBuffers.Add(CommandBuffer);
}

void CVulkanViewportWidgets::PreProcess(const TVector<SPreRenderViewportWidget> &AllViewportData)
{
    TVector<SPreRenderViewportWidget> ValidData;
    ValidData.Reserve(AllViewportData.Num());

    for (const auto& ViewportData : AllViewportData)
    {
        //检查数据是否合法
        if(ViewportData.Viewport.width<=0 || ViewportData.Viewport.height<=0)
        {
            continue;
        }

        //检查裁剪是否合法
        if(ViewportData.Scissor.extent.width<=0 || ViewportData.Scissor.extent.height<=0)
        {
            continue;
        }

        //如果裁剪矩形完全在视口外面，则不需要绘制
        if(ViewportData.Scissor.offset.x+ViewportData.Scissor.extent.width<=ViewportData.Viewport.x ||
            ViewportData.Scissor.offset.x>=ViewportData.Viewport.x+ViewportData.Viewport.width ||
            ViewportData.Scissor.offset.y+ViewportData.Scissor.extent.height<=ViewportData.Viewport.y ||
            ViewportData.Scissor.offset.y>=ViewportData.Viewport.y+ViewportData.Viewport.height)
        {
            continue;
        }

        ValidData.Add(ViewportData);

    };

    //创建渲染对象
    ViewportWidgets.Resize(ValidData.Num());
    for (int i = 0; i < ValidData.Num(); ++i)
    {
        ViewportWidgets[i].BindData(ValidData[i]);
    }

    //统计描述符

    //最终将渲染结果输出到屏幕上
    SVulkanDescriptorPoolSize PoolSize;
    PoolSize.SetNum= ViewportWidgets.Num();
    PoolSize+=CVulkanContext::Get()->GetImageWidgetDescriptorSetLayout().DescriptorNums*ViewportWidgets.Num();
    CVulkanContext::Get()->GetAutoResetDescriptorPool()->GenerallPool.PoolSize+=PoolSize;
    for(auto& Viewport: ViewportWidgets)
    {
        Viewport.Attachments->PrepareSelfRecord();
        if(Viewport.AntiAliasingAttachments)
        {
            Viewport.AntiAliasingAttachments->PrepareSelfRecord();
        }

    }

}

void CVulkanViewportWidgets::CreateSelfRecordTasks(CVulkanWindow *InRenderSurface, SRenderCommandBuffers &OutCmdBuffersToExecute)
{
    if(ViewportWidgets.Num()==0)
    {
        return;
    }

    //创建command buffer
    if(!CommandBuffer)
    {
        //allocate a command buffer for this widget
        vk::CommandBufferAllocateInfo CommandBufferAllocateInfo=vk::CommandBufferAllocateInfo()
            .setCommandPool(CVulkanContext::Get()->GetRenderThreadCommandPool())
            .setLevel(vk::CommandBufferLevel::ePrimary)
            .setCommandBufferCount(1);

        CommandBuffer = CVulkanContext::Get()->GetDevice().allocateCommandBuffers(CommandBufferAllocateInfo)[0];
    }


    OutCmdBuffersToExecute.SceneCommandBuffers.Add(CommandBuffer);

    
    vk::CommandBufferBeginInfo CmdBufferBeginInfo = vk::CommandBufferBeginInfo()
            .setFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit);

    CommandBuffer.begin(CmdBufferBeginInfo);
    

    for (auto& ViewportWidget : ViewportWidgets)
    {
        ViewportWidget.Draw(InRenderSurface,CommandBuffer);
    }

    CommandBuffer.end();

}

CVulkanViewportWidget::~CVulkanViewportWidget()
{
    if(Attachments)
    {
        delete Attachments;
        Attachments=nullptr;
    }
}

void CVulkanViewportWidget::BindData(const SPreRenderViewportWidget &InData)
{
    Data = InData;

    CalculateMathView();

    //创建Gbuffer 
    if(!Attachments)
    {
        Attachments = new CDefferRenderAttachments(ViewportSize);
    }
    else
    {
        //确保之前的g buffer大小和当前的视口大小一致
        vk::Extent2D GbufferSize2D=Attachments->ViewportSize;

        if(GbufferSize2D!=ViewportSize)
        {
            delete Attachments;
            Attachments = new CDefferRenderAttachments(ViewportSize);
        }
    }    

    //创建后处理抗锯齿附件
    if(Data.AntiAliasingMethod!=EAntiAliasingMethod::None)
    {
        if(!AntiAliasingAttachments)
        {
            AntiAliasingAttachments=new CAntiAliasingAttachments(ViewportSize);
        }
        else
        {
            if(AntiAliasingAttachments->ViewportSize!=ViewportSize)
            {
                delete AntiAliasingAttachments;
                AntiAliasingAttachments=new CAntiAliasingAttachments(ViewportSize);
            }
        }
    }
    else if(AntiAliasingAttachments)
    {
        delete AntiAliasingAttachments;
        AntiAliasingAttachments=nullptr;
    }

    ScenePainter.PreProcess(Data.Scenes,this);

    ForegroundMeshPainter.PreProcess(Data.ForegroundMeshInstances);

    if(Data.PixelObjects)
    {
        if(!PixelObjectGroup)
        {
            PixelObjectGroup=new CVulkanPixelObjectGroup();
        }

        PixelObjectGroup->PreProcess(
            Data.PixelObjects
            ,this
        );
    }
    else
    {
        PixelObjectGroup=nullptr;
    }
}

void CVulkanViewportWidget::Draw(CVulkanWindow *InRenderSurface,vk::CommandBuffer CommandBuffer)
{
    //创建gbuffer 描述符集
    Attachments->CreateDescriptorSet();

    ScenePainter.RecordCommand(
        CommandBuffer
        ,ViewportSize
        ,Parameters
        ,FrustumPoints
        ,Attachments
    );
    // Data.Scene->CreateRecordTasks(
    //     FrustumPoints,
    //     ViewportSize,
    //     Parameters,
    //     Attachments,
    //     CommandBuffer
    // ); 



    //convert gbuffer final image layout to shader read only optimal
    {
        vk::ImageMemoryBarrier ImageMemoryBarrier = vk::ImageMemoryBarrier()
            .setSrcAccessMask(vk::AccessFlagBits::eColorAttachmentWrite)
            .setDstAccessMask(vk::AccessFlagBits::eShaderRead)
            .setOldLayout(vk::ImageLayout::eColorAttachmentOptimal)
            .setNewLayout(vk::ImageLayout::eShaderReadOnlyOptimal)
            .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
            .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
            .setImage(Attachments->ShadeOutput->GetImage())
            .setSubresourceRange(vk::ImageSubresourceRange()
                .setAspectMask(vk::ImageAspectFlagBits::eColor)
                .setBaseMipLevel(0)
                .setLevelCount(1)
                .setBaseArrayLayer(0)
                .setLayerCount(1)
            );

        CommandBuffer.pipelineBarrier(
            vk::PipelineStageFlagBits::eColorAttachmentOutput,
            vk::PipelineStageFlagBits::eFragmentShader,
            vk::DependencyFlagBits::eByRegion,
            0, nullptr,
            0, nullptr,
            1, &ImageMemoryBarrier
        );
    }

    //抗锯齿
    //使用gbuffer的输出作为抗锯齿的输入
    if(Data.AntiAliasingMethod!=EAntiAliasingMethod::None)
    {
        AntiAliasingAttachments->CreateDescriptorSet(Attachments->ShadeOutput);

        vk::Rect2D RenderArea;
        RenderArea.offset.x=0;
        RenderArea.offset.y=0;
        RenderArea.extent=ViewportSize;
        
        auto RenderPassBeginInfo=vk::RenderPassBeginInfo()
            .setRenderPass(CVulkanContext::Get()->GetSceneGlobal()->AntiAliasingRenderPass)
            .setFramebuffer(AntiAliasingAttachments->FrameBuffer)
            .setRenderArea(RenderArea)
            .setClearValues(AntiAliasingAttachments->ClearValues);


        CommandBuffer.beginRenderPass(RenderPassBeginInfo, vk::SubpassContents::eInline);

        //set viewport
        vk::Viewport Viewport=vk::Viewport()
            .setX(RenderArea.offset.x)
            .setY(RenderArea.offset.y)
            .setWidth(RenderArea.extent.width)
            .setHeight(RenderArea.extent.height)
            .setMinDepth(0.0f)
            .setMaxDepth(1.0f);

        CommandBuffer.setViewport(0, Viewport);

        //bind pipeline
        CommandBuffer.bindPipeline(
            vk::PipelineBindPoint::eGraphics
            , CVulkanContext::Get()->GetSceneGlobal()->AntiAliasingPipeline);

        //bind descriptor set
        CommandBuffer.bindDescriptorSets(
            vk::PipelineBindPoint::eGraphics
            , CVulkanContext::Get()->GetSceneGlobal()->AntiAliasingPipelineLayout
            , 0
            ,1
            , &AntiAliasingAttachments->DescriptorSet
            ,0
            , nullptr);

        CommandBuffer.draw(4,1,0,0);

        CommandBuffer.endRenderPass();
    }


    //刷新最终渲染结果的descriptor set
    vk::DescriptorSet DescriptorSet;
    {
        //allocate descriptor set
        TVector<vk::DescriptorSetLayout> DescriptorSetLayouts=
        {
            CVulkanContext::Get()->GetImageWidgetDescriptorSetLayout().Layout
        };

        vk::DescriptorSetAllocateInfo DescriptorSetAllocateInfo = vk::DescriptorSetAllocateInfo()
            .setDescriptorPool(CVulkanContext::Get()->GetAutoResetDescriptorPool()->GenerallPool.Pool)
            .setSetLayouts(DescriptorSetLayouts);

        DescriptorSet = CVulkanContext::Get()->GetDevice().allocateDescriptorSets(DescriptorSetAllocateInfo)[0];
    
        //update descriptor set with final image of gbuffer
        vk::DescriptorImageInfo DescriptorImageInfo = vk::DescriptorImageInfo()
            .setSampler(CVulkanContext::Get()->GetSceneGlobal()->DefferRenderingOutputSampler)
            //.setImageView(AntiAliasingAttachments->AntialiasingOutput->GetImageView())
            .setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal);

        if(Data.AntiAliasingMethod==EAntiAliasingMethod::None)
        {
            DescriptorImageInfo.setImageView(Attachments->ShadeOutput->GetImageView());
        }
        else
        {
            DescriptorImageInfo.setImageView(AntiAliasingAttachments->AntialiasingOutput->GetImageView());
        }

        vk::WriteDescriptorSet WriteDescriptorSet = vk::WriteDescriptorSet()
            .setDstSet(DescriptorSet)
            .setDstBinding(0)
            .setDstArrayElement(0)
            .setDescriptorType(vk::DescriptorType::eCombinedImageSampler)
            .setDescriptorCount(1)
            .setPImageInfo(&DescriptorImageInfo);

        CVulkanContext::Get()->GetDevice().updateDescriptorSets(WriteDescriptorSet, nullptr);
    };

    //将最终的渲染结果作为输入，当做image widget一样渲染 
    {
        vk::ClearValue ClearValues[2];
        ClearValues[0].color.float32[0]=0.2f;
        ClearValues[0].color.float32[1]=0.2f;
        ClearValues[0].color.float32[2]=0.2f;
        ClearValues[0].color.float32[3]=1.0f;

        ClearValues[1].depthStencil.depth=1.0f;
        ClearValues[1].depthStencil.stencil=0;

        vk::Rect2D RenderArea;
        RenderArea.offset=vk::Offset2D(Data.Viewport.x,Data.Viewport.y); 
        RenderArea.extent=ViewportSize;
        //make sure every pixels in render area is in render surface
        if(RenderArea.offset.x+(int32_t)RenderArea.extent.width>(int32_t)InRenderSurface->GetSwapChainImageSize().width)
        {
            RenderArea.extent.width=(int32_t)InRenderSurface->GetSwapChainImageSize().width-RenderArea.offset.x;
        }

        if(RenderArea.offset.y+(int32_t)RenderArea.extent.height>(int32_t)InRenderSurface->GetSwapChainImageSize().height)
        {
            RenderArea.extent.height=(int32_t)InRenderSurface->GetSwapChainImageSize().height-RenderArea.offset.y;
        }

        auto RenderPassBeginInfo=vk::RenderPassBeginInfo()
            .setRenderPass(CVulkanContext::Get()->GetWidgetRenderPass())
            .setFramebuffer(InRenderSurface->GetCurrentFrameBuffer())
            .setRenderArea(RenderArea)
            .setClearValueCount(2)
            .setPClearValues(ClearValues);

        CommandBuffer.beginRenderPass(RenderPassBeginInfo, vk::SubpassContents::eInline);

    // //将抗锯齿的输出的布局转换为 eShaderReadOnlyOptimal
    // {
    //     vk::ImageMemoryBarrier ImageMemoryBarrier = vk::ImageMemoryBarrier()
    //         .setSrcAccessMask(vk::AccessFlagBits::eColorAttachmentWrite)
    //         .setDstAccessMask(vk::AccessFlagBits::eShaderRead)
    //         .setOldLayout(vk::ImageLayout::eColorAttachmentOptimal)
    //         .setNewLayout(vk::ImageLayout::eShaderReadOnlyOptimal)
    //         .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
    //         .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
    //         .setImage(AntiAliasingAttachments->AntialiasingOutput->GetImage())
    //         .setSubresourceRange(vk::ImageSubresourceRange()
    //             .setAspectMask(vk::ImageAspectFlagBits::eColor)
    //             .setBaseMipLevel(0)
    //             .setLevelCount(1)
    //             .setBaseArrayLayer(0)
    //             .setLayerCount(1)
    //         );

    //     CommandBuffer.pipelineBarrier(
    //         vk::PipelineStageFlagBits::eColorAttachmentOutput,
    //         vk::PipelineStageFlagBits::eFragmentShader,
    //         vk::DependencyFlagBits::eByRegion,
    //         0, nullptr,
    //         0, nullptr,
    //         1, &ImageMemoryBarrier
    //     );
    // }


        //set viewport
        CommandBuffer.setViewport(0, Data.Viewport);

        //bind pipeline
        CommandBuffer.bindPipeline(
            vk::PipelineBindPoint::eGraphics
            , CVulkanContext::Get()->GetImageWidgetPipeline());

        CommandBuffer.setScissor(0,1,&Data.Scissor);

        CVulkanContext::SImageWidgetVertexPushConstant PushConstantValue;
        PushConstantValue.ZOrder=Data.Depth;

        PushConstantValue.TintColor[0]=1.0f;
        PushConstantValue.TintColor[1]=1.0f;
        PushConstantValue.TintColor[2]=1.0f;
        PushConstantValue.TintColor[3]=1.0f;

        PushConstantValue.LeftTopUV[0]=0.0f;
        PushConstantValue.LeftTopUV[1]=0.0f;
        PushConstantValue.RightBottomUV[0]=1.0f;
        PushConstantValue.RightBottomUV[1]=1.0f;  

        CommandBuffer.pushConstants(
            CVulkanContext::Get()->GetImageWidgetPipelineLayout()
            , vk::ShaderStageFlagBits::eVertex
            , 0, sizeof(CVulkanContext::SImageWidgetVertexPushConstant), &PushConstantValue);

        //bind descriptor set
        CommandBuffer.bindDescriptorSets(
            vk::PipelineBindPoint::eGraphics
            , CVulkanContext::Get()->GetImageWidgetPipelineLayout()
            , 0
            ,1
            , &DescriptorSet
            ,0
            , nullptr);
   
        CommandBuffer.draw(4,1,0,0); 

        CommandBuffer.endRenderPass();               
    }

    //恢复抗锯齿输出的布局
    if(Data.AntiAliasingMethod!=EAntiAliasingMethod::None)
    {
        vk::ImageMemoryBarrier ImageMemoryBarrier = vk::ImageMemoryBarrier()
            .setSrcAccessMask(vk::AccessFlagBits::eShaderRead)
            .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentWrite)
            .setOldLayout(vk::ImageLayout::eShaderReadOnlyOptimal)
            .setNewLayout(vk::ImageLayout::eColorAttachmentOptimal)
            .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
            .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
            .setImage(AntiAliasingAttachments->AntialiasingOutput->GetImage())
            .setSubresourceRange(vk::ImageSubresourceRange()
                .setAspectMask(vk::ImageAspectFlagBits::eColor)
                .setBaseMipLevel(0)
                .setLevelCount(1)
                .setBaseArrayLayer(0)
                .setLayerCount(1)
            );

        CommandBuffer.pipelineBarrier(
            vk::PipelineStageFlagBits::eFragmentShader,
            vk::PipelineStageFlagBits::eColorAttachmentOutput,
            vk::DependencyFlagBits::eByRegion,
            0, nullptr,
            0, nullptr,
            1, &ImageMemoryBarrier
        );
    }



    if(Data.ForegroundMeshInstances.Num()>0)
    {
        //创建前景mesh的command buffer
        ForegroundMeshPainter.RecordCommand(
            CommandBuffer
            ,ViewMatrix
            ,ProjectionMatrix
            ,ViewportSize
        );

        vk::DescriptorSet ForegroundDescriptorSet;
        {
            //allocate descriptor set
            TVector<vk::DescriptorSetLayout> DescriptorSetLayouts=
            {
                CVulkanContext::Get()->GetImageWidgetDescriptorSetLayout().Layout
            };

            vk::DescriptorSetAllocateInfo DescriptorSetAllocateInfo = vk::DescriptorSetAllocateInfo()
                .setDescriptorPool(CVulkanContext::Get()->GetAutoResetDescriptorPool()->GenerallPool.Pool)
                .setSetLayouts(DescriptorSetLayouts);

            ForegroundDescriptorSet = CVulkanContext::Get()->GetDevice().allocateDescriptorSets(DescriptorSetAllocateInfo)[0];
        
            //update descriptor set with final image of gbuffer
            vk::DescriptorImageInfo DescriptorImageInfo = vk::DescriptorImageInfo()
                .setSampler(CVulkanContext::Get()->GetSceneGlobal()->DefferRenderingOutputSampler)
                .setImageView(CVulkanContext::Get()->GetForegroundMeshPipeline()->AxisColorRenderTarget->GetImageView()) 
                .setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal);

            vk::WriteDescriptorSet WriteDescriptorSet = vk::WriteDescriptorSet()
                .setDstSet(ForegroundDescriptorSet)
                .setDstBinding(0)
                .setDstArrayElement(0)
                .setDescriptorType(vk::DescriptorType::eCombinedImageSampler)
                .setDescriptorCount(1)
                .setPImageInfo(&DescriptorImageInfo);

            CVulkanContext::Get()->GetDevice().updateDescriptorSets(WriteDescriptorSet, nullptr);

        };
        //convert foreground final image layout to shader read only optimal
        {
            vk::ImageMemoryBarrier ImageMemoryBarrier = vk::ImageMemoryBarrier()
                .setSrcAccessMask(vk::AccessFlagBits::eColorAttachmentWrite)
                .setDstAccessMask(vk::AccessFlagBits::eShaderRead)
                .setOldLayout(vk::ImageLayout::eColorAttachmentOptimal)
                .setNewLayout(vk::ImageLayout::eShaderReadOnlyOptimal)
                .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
                .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
                .setImage(CVulkanContext::Get()->GetForegroundMeshPipeline()->AxisColorRenderTarget->GetImage())
                .setSubresourceRange(vk::ImageSubresourceRange()
                    .setAspectMask(vk::ImageAspectFlagBits::eColor)
                    .setBaseMipLevel(0)
                    .setLevelCount(1)
                    .setBaseArrayLayer(0)
                    .setLayerCount(1)
                );

            CommandBuffer.pipelineBarrier(
                vk::PipelineStageFlagBits::eColorAttachmentOutput,
                vk::PipelineStageFlagBits::eFragmentShader,
                vk::DependencyFlagBits::eByRegion,
                0, nullptr,
                0, nullptr,
                1, &ImageMemoryBarrier
            );
        }

        //use foreground final color as a fragment input and render it 
        //like a image widget
        {
            vk::ClearValue ClearValues[2];
            ClearValues[0].color.float32[0]=0.2f;
            ClearValues[0].color.float32[1]=0.2f;
            ClearValues[0].color.float32[2]=0.2f;
            ClearValues[0].color.float32[3]=1.0f;

            ClearValues[1].depthStencil.depth=1.0f;
            ClearValues[1].depthStencil.stencil=0;

            vk::Rect2D RenderArea;
            RenderArea.offset=vk::Offset2D(Data.Viewport.x,Data.Viewport.y); 
            RenderArea.extent=ViewportSize;

            //make sure every pixels in render area is in render surface
            if(RenderArea.offset.x+(int32_t)RenderArea.extent.width>(int32_t)InRenderSurface->GetSwapChainImageSize().width)
            {
                RenderArea.extent.width=(int32_t)InRenderSurface->GetSwapChainImageSize().width-RenderArea.offset.x;
            }

            if(RenderArea.offset.y+(int32_t)RenderArea.extent.height>(int32_t)InRenderSurface->GetSwapChainImageSize().height)
            {
                RenderArea.extent.height=(int32_t)InRenderSurface->GetSwapChainImageSize().height-RenderArea.offset.y;
            }

            auto RenderPassBeginInfo=vk::RenderPassBeginInfo()
                .setRenderPass(CVulkanContext::Get()->GetWidgetRenderPass())
                .setFramebuffer(InRenderSurface->GetCurrentFrameBuffer())
                .setRenderArea(RenderArea)
                .setClearValueCount(2)
                .setPClearValues(ClearValues);

            CommandBuffer.beginRenderPass(RenderPassBeginInfo, vk::SubpassContents::eInline);

            //set viewport
            vk::Viewport Viewport=vk::Viewport()
                .setX(RenderArea.offset.x)
                .setY(RenderArea.offset.y)
                .setWidth(RenderArea.extent.width)
                .setHeight(RenderArea.extent.height)
                .setMinDepth(0.0f)
                .setMaxDepth(1.0f);

            CommandBuffer.setViewport(0, Viewport);

            //bind pipeline
            CommandBuffer.bindPipeline(
                vk::PipelineBindPoint::eGraphics
                , CVulkanContext::Get()->GetImageWidgetPipeline());

            CommandBuffer.setScissor(0,1,&Data.Scissor);

            CVulkanContext::SImageWidgetVertexPushConstant PushConstantValue;
            PushConstantValue.ZOrder=Data.Depth;

            PushConstantValue.LeftTopUV[0]=0.0f;
            PushConstantValue.LeftTopUV[1]=0.0f;
            PushConstantValue.RightBottomUV[0]=1.0f;
            PushConstantValue.RightBottomUV[1]=1.0f;

            CommandBuffer.pushConstants(
                CVulkanContext::Get()->GetImageWidgetPipelineLayout()
                , vk::ShaderStageFlagBits::eVertex
                , 0, sizeof(CVulkanContext::SImageWidgetVertexPushConstant), &PushConstantValue);

            //bind descriptor set
            CommandBuffer.bindDescriptorSets(
                vk::PipelineBindPoint::eGraphics
                , CVulkanContext::Get()->GetImageWidgetPipelineLayout()
                , 0
                ,1
                , &ForegroundDescriptorSet
                ,0
                , nullptr);

            CommandBuffer.draw(4,1,0,0);

            CommandBuffer.endRenderPass();
        }

        //convert foreground final image layout back to  color attachment optimal
        {
            vk::ImageMemoryBarrier ImageMemoryBarrier = vk::ImageMemoryBarrier()
                .setSrcAccessMask(vk::AccessFlagBits::eShaderRead)
                .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentWrite)
                .setOldLayout(vk::ImageLayout::eShaderReadOnlyOptimal)
                .setNewLayout(vk::ImageLayout::eColorAttachmentOptimal)
                .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
                .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
                .setImage(CVulkanContext::Get()->GetForegroundMeshPipeline()->AxisColorRenderTarget->GetImage())
                .setSubresourceRange(vk::ImageSubresourceRange()
                    .setAspectMask(vk::ImageAspectFlagBits::eColor)
                    .setBaseMipLevel(0)
                    .setLevelCount(1)
                    .setBaseArrayLayer(0)
                    .setLayerCount(1)
                );

            CommandBuffer.pipelineBarrier(
                vk::PipelineStageFlagBits::eFragmentShader,
                vk::PipelineStageFlagBits::eColorAttachmentOutput,
                vk::DependencyFlagBits::eByRegion,
                0, nullptr,
                0, nullptr,
                1, &ImageMemoryBarrier
            );
        }

    }


    //绘制pixel objects
    if(PixelObjectGroup)
    {
        PixelObjectGroup->Draw(CommandBuffer);
    }
}

void CVulkanViewportWidget::CalculateMathView()
{
    ViewportSize=vk::Extent2D(Data.Viewport.width,Data.Viewport.height);

    ViewMatrix=Data.CameraParameters.ViewMatrix;
    ProjectionMatrix=Data.CameraParameters.ProjectionMatrix;
   

    float _Near= Data.CameraParameters.RawParameters.Near;
    float _Far= Data.CameraParameters.RawParameters.Far;
    if(Data.CameraParameters.RawParameters.ProjectionType==EProjectionType::Perspective)
    {
        //create frustum points
        
        SVec3 RightDirection = Data.CameraParameters.RawParameters.ViewportRotation.GetRightDirection();
        SVec3 UpDirection= Data.CameraParameters.RawParameters.ViewportRotation.GetUpDirection();
        SVec3 ForwardDirection= Data.CameraParameters.RawParameters.ViewportRotation.GetForwardDirection();


        float _FOVY=Data.CameraParameters.RawParameters.PerspectiveFOVY;

        SVec3 NearPlanCenter= Data.CameraParameters.RawParameters.ViewportPosition
            +ForwardDirection*_Near;

        SVec3 FarPlanCenter= Data.CameraParameters.RawParameters.ViewportPosition
            +ForwardDirection*_Far;

        float NearPlanHeight=2.0f*_Near*CMathBase::Tan(_FOVY*0.5f);

        float NearPlanWidth=NearPlanHeight*Data.CameraParameters.RawParameters.AspectRatio;

        float FarPlanHeight=2.0f*_Far*CMathBase::Tan(_FOVY*0.5f);

        float FarPlanWidth=FarPlanHeight*Data.CameraParameters.RawParameters.AspectRatio;

        FrustumPoints.LeftTopNear=NearPlanCenter
            +UpDirection*(NearPlanHeight*0.5f)
            -RightDirection*(NearPlanWidth*0.5f);

        FrustumPoints.RightTopNear=NearPlanCenter
            +UpDirection*(NearPlanHeight*0.5f)
            +RightDirection*(NearPlanWidth*0.5f);

        FrustumPoints.LeftBottomNear=NearPlanCenter
            -UpDirection*(NearPlanHeight*0.5f)
            -RightDirection*(NearPlanWidth*0.5f);

        FrustumPoints.RightBottomNear=NearPlanCenter
            -UpDirection*(NearPlanHeight*0.5f)
            +RightDirection*(NearPlanWidth*0.5f);

        FrustumPoints.LeftTopFar=FarPlanCenter
            +UpDirection*(FarPlanHeight*0.5f)
            -RightDirection*(FarPlanWidth*0.5f);

        FrustumPoints.RightTopFar=FarPlanCenter
            +UpDirection*(FarPlanHeight*0.5f)
            +RightDirection*(FarPlanWidth*0.5f);

        FrustumPoints.LeftBottomFar=FarPlanCenter
            -UpDirection*(FarPlanHeight*0.5f)
            -RightDirection*(FarPlanWidth*0.5f);

        FrustumPoints.RightBottomFar=FarPlanCenter
            -UpDirection*(FarPlanHeight*0.5f)
            +RightDirection*(FarPlanWidth*0.5f);
    }
    else
    {
        //create frustum points
        SVec3 RightDirection = Data.CameraParameters.RawParameters.ViewportRotation.GetRightDirection();
        SVec3 UpDirection= Data.CameraParameters.RawParameters.ViewportRotation.GetUpDirection();
        SVec3 ForwardDirection= Data.CameraParameters.RawParameters.ViewportRotation.GetForwardDirection();

        float _OrthographicWidth=Data.CameraParameters.RawParameters.OrthographicWidth;

        SVec3 NearPlanCenter= Data.CameraParameters.RawParameters.ViewportPosition
            +ForwardDirection*_Near;

        SVec3 FarPlanCenter= Data.CameraParameters.RawParameters.ViewportPosition
            +ForwardDirection*_Far;

        float NearPlanHeight=_OrthographicWidth*Data.CameraParameters.RawParameters.AspectRatio;

        float NearPlanWidth=_OrthographicWidth;

        float FarPlanHeight=_OrthographicWidth*Data.CameraParameters.RawParameters.AspectRatio;

        float FarPlanWidth=_OrthographicWidth;

        FrustumPoints.LeftTopNear=NearPlanCenter
            +UpDirection*(NearPlanHeight*0.5f)
            -RightDirection*(NearPlanWidth*0.5f);

        FrustumPoints.RightTopNear=NearPlanCenter
            +UpDirection*(NearPlanHeight*0.5f)
            +RightDirection*(NearPlanWidth*0.5f);

        FrustumPoints.LeftBottomNear=NearPlanCenter
            -UpDirection*(NearPlanHeight*0.5f)
            -RightDirection*(NearPlanWidth*0.5f);

        FrustumPoints.RightBottomNear=NearPlanCenter
            -UpDirection*(NearPlanHeight*0.5f)
            +RightDirection*(NearPlanWidth*0.5f);

        FrustumPoints.LeftTopFar=FarPlanCenter
            +UpDirection*(FarPlanHeight*0.5f)
            -RightDirection*(FarPlanWidth*0.5f);

        FrustumPoints.RightTopFar=FarPlanCenter
            +UpDirection*(FarPlanHeight*0.5f)
            +RightDirection*(FarPlanWidth*0.5f);

        FrustumPoints.LeftBottomFar=FarPlanCenter
            -UpDirection*(FarPlanHeight*0.5f)
            -RightDirection*(FarPlanWidth*0.5f);

        FrustumPoints.RightBottomFar=FarPlanCenter
            -UpDirection*(FarPlanHeight*0.5f)
            +RightDirection*(FarPlanWidth*0.5f);

    }



    //set scene parameters
    ProjectionMatrix.ToFloatArray(Parameters.ProjectMatrix);
    ViewMatrix.ToFloatArray(Parameters.ViewMatrix);
    (ProjectionMatrix*ViewMatrix).ToFloatArray(Parameters.ProjectViewMatrix);
    Parameters.CameraNearPlane=_Near;
    Parameters.CameraFarPlane=_Far;
    Data.CameraParameters.RawParameters.ViewportPosition.ToFloatArray(Parameters.CameraPosition);
    //Data.CameraParameters.RawParameters.ViewportRotation.ToFloatArray(Parameters.CameraRotation);
    Data.CameraParameters.RawParameters.ViewportRotation.GetForwardDirection().ToFloatArray(Parameters.CameraForwardDirection);
    Data.CameraParameters.RawParameters.ViewportRotation.GetRightDirection().ToFloatArray(Parameters.CameraRightDirection);
    Data.CameraParameters.RawParameters.ViewportRotation.GetUpDirection().ToFloatArray(Parameters.CameraUpDirection);


}

bool CVulkanViewportWidget::FastIsSphereIntersectFrustum(const SVec3 &InCenter, float InRadius)
{

    float _Near= Data.CameraParameters.RawParameters.Near;
    float _Far= Data.CameraParameters.RawParameters.Far;

    if(Data.CameraParameters.RawParameters.ProjectionType==EProjectionType::Perspective)
    {
        //透视投影
        //将球心投影到视图坐标系上

        SVec3 NewCenter= ViewMatrix*InCenter;


        if(NewCenter.Y>(_Far+InRadius) || NewCenter.Y<(_Near-InRadius))
        {
            return false;
        }

        float _Aspect=Data.CameraParameters.RawParameters.AspectRatio;
        float _FOVY=
            CMathBase::DegreeToRadian(Data.CameraParameters.RawParameters.PerspectiveFOVY);

        //不知道为什么计算用视椎体高度和宽度小于实际的视椎体高度和宽度
        //所以放大FOV
        _FOVY*=1.1f;

        //求球心最大高度(Z)
        float MaxZ=CMath::Tan(_FOVY*0.5f)*CMath::Abs(NewCenter.Y)
            +InRadius / CMath::Cos(_FOVY*0.5f);

        if(MaxZ<CMath::Abs(NewCenter.Z))
        {
            return false;
        }


        //求球心最大宽度(X)
        float _FOVX=_FOVY * _Aspect;
        float MaxX=CMath::Tan(_FOVX*0.5f)*CMath::Abs(NewCenter.Y)
            +InRadius / CMath::Cos(_FOVX*0.5f);

        if(MaxX<CMath::Abs(NewCenter.X))
        {
            return false;
        }

        return true;
    }
    else
    {
        //正交投影
        //视椎体是一个长方体，设长方体坐标系原点为长方体的中心,+X轴为右，+Z轴向上

        //将球心投影到长方体坐标系上
        SVec3 NewCenter= ViewMatrix*InCenter;
        NewCenter.Y+=  (_Near+_Far) *0.5;


        SVec3 FrustumSize=FrustumPoints.RightTopNear-FrustumPoints.LeftBottomNear;
        FrustumSize.X=CMath::Abs(FrustumSize.X);
        FrustumSize.Y=CMath::Abs(FrustumSize.Y);
        FrustumSize.Z=CMath::Abs(FrustumSize.Z);

        if(CMath::Abs(NewCenter.X) > FrustumSize.X+InRadius)
        {
            return false;
        }

        if(CMath::Abs(NewCenter.Y) > FrustumSize.Y+InRadius)
        {
            return false;
        }

        if(CMath::Abs(NewCenter.Z) > FrustumSize.Z+InRadius)
        {
            return false;
        }

        //依然有可能不想交，简化计算
        return true;

    }
}